package com.summer.filesync.network;

import com.summer.filesync.config.ConfigManager;
import com.summer.filesync.config.SystemConfig;
import com.summer.filesync.model.Message;
import com.summer.filesync.util.Logger;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/** 网络管理器 负责管理网络连接、消息收发和节点管理 */
public class NetworkManager {

  private static final Logger logger = Logger.getLogger(NetworkManager.class);
  private static NetworkManager instance;
  private static final Object INSTANCE_LOCK = new Object();

  private ServerSocket serverSocket;
  private ExecutorService serverThreadPool;
  private ExecutorService clientThreadPool;
  private ConcurrentHashMap<String, NodeConnection> connectedNodes;
  private BlockingQueue<Message> incomingMessageQueue;
  private BlockingQueue<Message> outgoingMessageQueue;
  private HeartbeatService heartbeatService;
  private MessageProcessor messageProcessor;

  private boolean isRunning = false;
  private int serverPort;
  private String localNodeId;

  private NetworkManager() {
    ConfigManager config = ConfigManager.getInstance();
    this.serverPort =
        config.getIntProperty(SystemConfig.NETWORK_PORT, SystemConfig.Defaults.NETWORK_PORT);
    this.localNodeId = config.getProperty(SystemConfig.NODE_ID, "");
    this.connectedNodes = new ConcurrentHashMap<>();
    this.incomingMessageQueue = new LinkedBlockingQueue<>();
    this.outgoingMessageQueue = new LinkedBlockingQueue<>();

    int maxConnections =
        config.getIntProperty(SystemConfig.MAX_CONNECTIONS, SystemConfig.Defaults.MAX_CONNECTIONS);
    this.serverThreadPool = Executors.newFixedThreadPool(maxConnections);
    this.clientThreadPool = Executors.newFixedThreadPool(5);
  }

  /** 获取单例实例 */
  public static NetworkManager getInstance() {
    if (instance == null) {
      synchronized (INSTANCE_LOCK) {
        if (instance == null) {
          instance = new NetworkManager();
        }
      }
    }
    return instance;
  }

  /** 启动网络服务 */
  public synchronized void start() throws IOException {
    if (isRunning) {
      logger.warn("NetworkManager is already running");
      return;
    }

    logger.info("Starting NetworkManager on port " + serverPort);

    // 启动服务器
    startServer();

    // 启动心跳服务
    heartbeatService = new HeartbeatService(this);
    clientThreadPool.submit(heartbeatService);

    // 启动消息处理器
    messageProcessor = new MessageProcessor(this);
    clientThreadPool.submit(messageProcessor);

    isRunning = true;
    logger.info("NetworkManager started successfully");
  }

  /** 启动服务器监听 */
  private void startServer() throws IOException {
    serverSocket = new ServerSocket(serverPort);

    // 启动服务器接受连接的线程
    clientThreadPool.submit(
        () -> {
          logger.info("Server listening on port " + serverPort);

          while (isRunning && !serverSocket.isClosed()) {
            try {
              Socket clientSocket = serverSocket.accept();
              logger.info("New connection from: " + clientSocket.getRemoteSocketAddress());

              // 为新连接创建处理线程
              serverThreadPool.submit(() -> handleNewConnection(clientSocket));

            } catch (IOException e) {
              if (isRunning) {
                logger.error("Error accepting connection", e);
              }
            }
          }
        });
  }

  /** 处理新连接 */
  private void handleNewConnection(Socket socket) {
    try {
      // 创建节点连接
      NodeConnection connection = new NodeConnection(socket, this);

      // 等待对方发送节点信息
      Message handshakeMessage = connection.receiveMessage();
      if (handshakeMessage != null && handshakeMessage.getType() == Message.MessageType.NODE_JOIN) {
        String remoteNodeId = handshakeMessage.getSourceNodeId();

        // 注册连接
        connectedNodes.put(remoteNodeId, connection);
        logger.info("Node connected: " + remoteNodeId);

        // 发送确认消息
        Message ackMessage =
            new Message(Message.MessageType.NODE_JOIN, localNodeId, remoteNodeId, "ACK");
        connection.sendMessage(ackMessage);

        // 启动连接处理器
        serverThreadPool.submit(new ConnectionHandler(connection, this));
      } else {
        logger.warn("Invalid handshake from: " + socket.getRemoteSocketAddress());
        socket.close();
      }

    } catch (Exception e) {
      logger.error("Error handling new connection", e);
      try {
        socket.close();
      } catch (IOException ex) {
        logger.error("Error closing socket", ex);
      }
    }
  }

  /** 连接到远程节点 */
  public boolean connectToNode(String nodeId, String host, int port) {
    if (connectedNodes.containsKey(nodeId)) {
      logger.warn("Already connected to node: " + nodeId);
      return true;
    }

    try {
      logger.info("Connecting to node: " + nodeId + " at " + host + ":" + port);

      Socket socket = new Socket(host, port);
      NodeConnection connection = new NodeConnection(socket, this);

      // 发送握手消息
      Message handshakeMessage =
          new Message(Message.MessageType.NODE_JOIN, localNodeId, nodeId, localNodeId);
      connection.sendMessage(handshakeMessage);

      // 等待确认
      Message ackMessage = connection.receiveMessage();
      if (ackMessage != null && "ACK".equals(ackMessage.getPayload())) {
        connectedNodes.put(nodeId, connection);
        logger.info("Successfully connected to node: " + nodeId);

        // 启动连接处理器
        clientThreadPool.submit(new ConnectionHandler(connection, this));
        return true;
      } else {
        logger.error("Failed to get handshake acknowledgment from: " + nodeId);
        socket.close();
        return false;
      }

    } catch (Exception e) {
      logger.error("Error connecting to node: " + nodeId, e);
      return false;
    }
  }

  /** 断开与指定节点的连接 */
  public void disconnectNode(String nodeId) {
    NodeConnection connection = connectedNodes.remove(nodeId);
    if (connection != null) {
      try {
        // 发送离开消息
        Message leaveMessage =
            new Message(Message.MessageType.NODE_LEAVE, localNodeId, nodeId, "GOODBYE");
        connection.sendMessage(leaveMessage);

        connection.close();
        logger.info("Disconnected from node: " + nodeId);
      } catch (Exception e) {
        logger.error("Error disconnecting from node: " + nodeId, e);
      }
    }
  }

  /** 发送消息到指定节点 */
  public boolean sendMessage(String nodeId, Message message) {
    NodeConnection connection = connectedNodes.get(nodeId);
    if (connection == null) {
      logger.warn("No connection to node: " + nodeId);
      return false;
    }

    try {
      connection.sendMessage(message);
      return true;
    } catch (Exception e) {
      logger.error("Error sending message to node: " + nodeId, e);
      // 连接可能已断开，移除连接
      connectedNodes.remove(nodeId);
      return false;
    }
  }

  /** 广播消息到所有连接的节点 */
  public void broadcastMessage(Message message) {
    if (connectedNodes.isEmpty()) {
      logger.debug("No connected nodes to broadcast to");
      return;
    }

    logger.debug("Broadcasting message to " + connectedNodes.size() + " nodes");

    for (String nodeId : connectedNodes.keySet()) {
      sendMessage(nodeId, message);
    }
  }

  /** 获取所有在线节点 */
  public Set<String> getOnlineNodes() {
    return connectedNodes.keySet();
  }

  /** 获取连接的节点数量 */
  public int getConnectedNodeCount() {
    return connectedNodes.size();
  }

  /** 获取所有连接的节点ID */
  public Set<String> getConnectedNodeIds() {
    return Set.copyOf(connectedNodes.keySet());
  }

  /** 获取传出消息队列 */
  public BlockingQueue<Message> getOutgoingMessageQueue() {
    return outgoingMessageQueue;
  }

  /** 添加传入消息到队列 */
  public void addIncomingMessage(Message message) {
    try {
      incomingMessageQueue.put(message);
    } catch (InterruptedException e) {
      logger.error("Error adding incoming message to queue", e);
      Thread.currentThread().interrupt();
    }
  }

  /** 获取传入消息队列 */
  public BlockingQueue<Message> getIncomingMessageQueue() {
    return incomingMessageQueue;
  }

  /** 处理节点连接断开 */
  public void handleConnectionLost(String nodeId) {
    NodeConnection connection = connectedNodes.remove(nodeId);
    if (connection != null) {
      try {
        connection.close();
      } catch (Exception e) {
        logger.error("Error closing connection for node: " + nodeId, e);
      }
      logger.info("Connection lost with node: " + nodeId);
    }
  }

  /** 停止网络服务 */
  public synchronized void shutdown() {
    if (!isRunning) {
      return;
    }

    logger.info("Shutting down NetworkManager...");
    isRunning = false;

    // 断开所有连接
    for (String nodeId : connectedNodes.keySet()) {
      disconnectNode(nodeId);
    }

    // 关闭服务器
    try {
      if (serverSocket != null && !serverSocket.isClosed()) {
        serverSocket.close();
      }
    } catch (IOException e) {
      logger.error("Error closing server socket", e);
    }

    // 停止心跳服务
    if (heartbeatService != null) {
      heartbeatService.stop();
    }

    // 停止消息处理器
    if (messageProcessor != null) {
      messageProcessor.stop();
    }

    // 关闭线程池
    serverThreadPool.shutdown();
    clientThreadPool.shutdown();

    logger.info("NetworkManager shutdown completed");
  }

  /** 检查是否正在运行 */
  public boolean isRunning() {
    return isRunning;
  }

  /** 获取本地节点ID */
  public String getLocalNodeId() {
    return localNodeId;
  }
}
